/*
 * FileName:    HibernateCommonDao.java
 * Description: ICommonDaoのHibernate実現
 * History:     2010-8-23 (廖宝俊) 1.0 Create
 */
package com.sn.system.common.dao.hibernate;

import java.io.Serializable;

import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import com.sn.system.common.command.Page;
import com.sn.system.common.dao.ICommonDao;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;

/**
 * The <code>HibernateCommonDao</code> class ICommonDaoのHibernate実現
 *
 * @author  廖宝俊
 * @version 1.0, 2010-8-23
 */
public class HibernateCommonDao implements ICommonDao {

	private SessionFactory sessionFactory;  
	


	/**
     * 対象を新たに増加する
     * @param entity   増加された対象
     */
    public void insert(Object entity) {
    	sessionFactory.getCurrentSession().save(entity);
    }

    /**
	 * 更新対象
	 * @param entity　　　更新された対象
	 */
    public void update(Object entity) {
    	sessionFactory.getCurrentSession().update(entity);
    }

    /**
     * 登録対象
     * @param entity    登録された対象
     */
    public void save(Object entity) {
    	sessionFactory.getCurrentSession().saveOrUpdate(entity);
    	sessionFactory.getCurrentSession().flush();
    }

    /**
     * 登録対象、後再びデータベースからこの対象を読み取ります。
     * @param entity    登録された対象
     */
    public void saveAndRefresh(Object entity) {
    	sessionFactory.getCurrentSession().saveOrUpdate(entity);
    	sessionFactory.getCurrentSession().flush();
    	sessionFactory.getCurrentSession().refresh(entity);
    }

    /**
     * 登録対象集合
     * @param entities  登録された対象集合
     */
    public void saveAll(Collection entities) {
    	//sessionFactory.getCurrentSession().saveOrUpdateAll(entities);
    }

    /**
     * 削除対象
     * @param entity    削除された対象
     */
    public void delete(Object entity) {
        sessionFactory.getCurrentSession().delete(entity);
        sessionFactory.getCurrentSession().flush();
    }

    /**
     * 削除対象集合
     * @param entities  削除された対象集合
     */
    public void deleteAll(Collection entities) {
        //sessionFactory.getCurrentSession().deleteAll(entities);
        sessionFactory.getCurrentSession().flush();
        sessionFactory.getCurrentSession().clear();
    }

    /**
     * sessionをクリア
     */
    public void sessionClear() {
        sessionFactory.getCurrentSession().clear();
    }


    /**
     * １つの対象を取ります
     * @param entityClass   対象のクラス
     * @param id            キー
     * @return  対象
     */
    public Object load(Class entityClass, Serializable id) {
    	return sessionFactory.getCurrentSession().load(entityClass, id);
    }

    /**
     * １つの対象を検索します
     * @param entityClass   対象のクラス
     * @param id            キー
     * @return  対象
     */
    public Object get(Class entityClass, Serializable id) {
    	return sessionFactory.getCurrentSession().get(entityClass, id);
    }

    /** 指定するクラスの全部対象を取ります
     * @param entityClass クラス
     * @return 対象リスト
     */
    public <T> List<T>  loadAll(Class<T>  entityClass,String... orderStr) {

    	Session session = sessionFactory.getCurrentSession();
    	//Session session = sessionFactory.openSession();
    	
    	Criteria criteria = session.createCriteria(entityClass);
    	
    	if(orderStr==null||orderStr.length==0){

    	}else{
    		for(int i=0;i<orderStr.length;i++){
    			String[] order=orderStr[i].split(",");
    			if(order.length==2){
    				if(order[1].equals("asc")){
    					criteria.addOrder(Order.asc(order[0]));
    				}else if(order[1].equals("desc")){
    					criteria.addOrder(Order.desc(order[0]));
    				}
    			}else if(order.length==1){
    				criteria.addOrder(Order.asc(order[0]));
    			}
    		}
    	}
    	List<T> list = criteria.list();
		return list;
    }

    /**
     * 検索の文を実行します
     * @param queryString 検索の文
     * @param values        パラメーター
     * @return 対象リスト
     */
    public List executeSql(final String queryString, final Object... Conditions) {
//    	List data = (List) sessionFactory.getCurrentSession().execute(
//                new HibernateCallback() {
//                    public Object doInHibernate(Session session) throws HibernateException {
//                        Query queryObject = session.createQuery(queryString);
//                        for (int i = 0; i < Conditions.length; ++i) {
//                        	if(Conditions[i] instanceof Collection){
//                        		queryObject.setParameterList("inList"+i, (Collection)Conditions[i]);
//                        	}else{
//                        		queryObject.setParameter(i, Conditions[i]);
//                        	}
//                        }
//                        return queryObject.list();
//                    }
//                }, true);
//    	List data = (List) sessionFactory.getCurrentSession().execute(
//                new HibernateCallback() {
//                    public Object doInHibernate(Session session) throws HibernateException {
//                        Query queryObject = session.createQuery(queryString);
//                        for (int i = 0; i < Conditions.length; ++i) {
//                        	if(Conditions[i] instanceof Collection){
//                        		queryObject.setParameterList("inList"+i, (Collection)Conditions[i]);
//                        	}else{
//                        		queryObject.setParameter(i, Conditions[i]);
//                        	}
//                        }
//                        return queryObject.list();
//                    }
//                });
    	
//    	if(Conditions.length>0){
//    		return sessionFactory.getCurrentSession().find(queryString, Conditions);		
//    	}else{
//    		return sessionFactory.getCurrentSession().find(queryString);
//    	}
    	sessionFactory.getCurrentSession().flush();
        sessionFactory.getCurrentSession().clear();
//    	return data;
        return null;
    }
    private boolean ifListInConditions(Object[] Conditions){
    	for(Object con:Conditions){
    		if(con instanceof java.util.List||con instanceof String[]){
    			return true;
    		}
    	}
    	return false;
    }


//////////ページを分ける検索
    /** from マーク     */
    private static String sqlFromToken = " from ";
    /** select マーク     */
    private static String sqlSelectToken = "select ";
    /** distinct マーク     */
    private static String sqlDistinctToken = "distinct";
    /** group by マーク     */
    private static String sqlGroupByToken = "group by ";
    /** order by マーク     */
    private static String sqlOrderByToken = "order by ";

    /**
     * null
     */
    private static final int NULL_DEFAULTSIZE = -1;

    /** 既定のページサイズ */
    private int defaultSize = NULL_DEFAULTSIZE;

    public int getDefaultSize() {
    	this.defaultSize=10;
        return this.defaultSize;
    }

    /**
     * 総データー数の検索HSQL取りる
     * @param queryString   検索のHSQL文
     * @return  総データー数の検索HSQL
     */
    private String getCountString(final String queryString) {
        String countTokenString = "*";
        String targetString = queryString.toLowerCase();
        int fromPos = targetString.indexOf(sqlFromToken);
        String fromTokenString = queryString.substring((fromPos < 0) ? 0 : fromPos);
        int orderPos = fromTokenString.indexOf(sqlOrderByToken);
        if (orderPos > 0) {
            fromTokenString = fromTokenString.substring(0, orderPos);
        }
        if (fromPos > 0) {
            int selectPos = targetString.indexOf(sqlSelectToken);
            int distinctPos = targetString.indexOf(sqlDistinctToken);
            if (selectPos >= 0 && distinctPos >= 0) {
                countTokenString = queryString.substring(selectPos + sqlSelectToken.length(), fromPos);
                String[] tokenArray = countTokenString.split(",");
                if (tokenArray.length > 0) {
                    countTokenString = tokenArray[0];
                }
            }

        }
        return new StringBuffer().append("select count(").append(countTokenString).append(") ")
        .append(fromTokenString).toString();
    }

    /** 総記録数の検索HSQLを実施
     * @param countString 検索の文
     * @param Conditions 検索の条件
     * @return iterator 戻るのイテレータ
     */
    private Iterator getCountIterator (final String countString, final Object... Conditions) {
//    	Iterator iterator=((List) sessionFactory.getCurrentSession().execute(
//                new HibernateCallback() {
//                    public Object doInHibernate(Session session) throws HibernateException {
//                        Query queryObject = session.createQuery(countString);
//                        for (int i = 0; i < Conditions.length; ++i) {
//                        	if(Conditions[i] instanceof java.util.List){
//                        		queryObject.setParameterList("inList"+i, (java.util.List)Conditions[i]);
//                        	}else{
//                        		queryObject.setParameter(i, Conditions[i]);
//                        	}
//                        }
//                        return queryObject.list();
//                    }
//                }, true)).iterator();
//    	Iterator iterator=((List) sessionFactory.getCurrentSession().execute(
//                new HibernateCallback() {
//                    public Object doInHibernate(Session session) throws HibernateException {
//                        Query queryObject = session.createQuery(countString);
//                        for (int i = 0; i < Conditions.length; ++i) {
//                        	if(Conditions[i] instanceof java.util.List){
//                        		queryObject.setParameterList("inList"+i, (java.util.List)Conditions[i]);
//                        	}else{
//                        		queryObject.setParameter(i, Conditions[i]);
//                        	}
//                        }
//                        return queryObject.list();
//                    }
//                })).iterator();
//        return iterator;
return null;
    }

    /** 総記録数を得る
     * @param queryString 検索の文
     * @param iterator 総記録数の検索HSQLを実施した後戻るのイテレータ
     * @return 総記録数
     */
    private int getRecordNumber(final String queryString, Iterator iterator) {
        int recordNumber = 0;
        if (queryString.indexOf(sqlGroupByToken) > 0) {
            while (iterator.hasNext()) {
                recordNumber++;
                iterator.next();
            }
        } else if (iterator.hasNext()) {
             recordNumber = ((Long) iterator.next()).intValue();
        }
//        if (!(iterator instanceof EmptyIterator)) {
//            sessionFactory.getCurrentSession().closeIterator(iterator);
//        }
        return recordNumber;

    }


    /**
     * @param queryString       HSQL
     * @param pageNumber        当面のページ番号
     * @param Conditions        検索の条件
     * @return  Page実例
     */
    public Page find(final String queryString,final int pageNumber, final Object... Conditions) {
    	return this.find(queryString, pageNumber, getDefaultSize(), Conditions);
    }

    /**
     * @param queryString       HSQL
     * @param pageNumber        当面のページ番号
     * @param pageSize           ページサイズ
     * @param Conditions        検索の条件
     * @return  Page実例
     */
    public Page find(final String queryString,final int pageNumber, final int pageSize, final Object... Conditions) {

    	//Iterator iterator =sessionFactory.getCurrentSession().iterate(this.getCountString(queryString), Conditions);

    	final String countString=this.getCountString(queryString).replace("join fetch", "join ");
    	Iterator iterator=getCountIterator(countString,Conditions);

        int recordNumber = this.getRecordNumber(queryString, iterator);

        if (recordNumber == 0) {
            return new HibernatePage();
        }

        final HibernatePage page = new HibernatePage(pageSize, pageNumber, recordNumber);

//        List data = (List) sessionFactory.getCurrentSession().execute(
//                new HibernateCallback() {
//                    public Object doInHibernate(Session session) throws HibernateException {
//                        Query queryObject = session.createQuery(queryString);
//                        for (int i = 0; i < Conditions.length; ++i) {
//                        	if(Conditions[i] instanceof java.util.List){
//                        		queryObject.setParameterList("inList"+i, (java.util.List)Conditions[i]);
//                        	}else{
//                        		queryObject.setParameter(i, Conditions[i]);
//                        	}
//                        }
//                        queryObject.setFirstResult((page.getPageNumber() - 1) * pageSize);
//                        queryObject.setMaxResults(pageSize);
//                        return queryObject.list();
//                    }
//                }, true);
//        List data = (List) sessionFactory.getCurrentSession().execute(
//                new HibernateCallback() {
//                    public Object doInHibernate(Session session) throws HibernateException {
//                        Query queryObject = session.createQuery(queryString);
//                        for (int i = 0; i < Conditions.length; ++i) {
//                        	if(Conditions[i] instanceof java.util.List){
//                        		queryObject.setParameterList("inList"+i, (java.util.List)Conditions[i]);
//                        	}else{
//                        		queryObject.setParameter(i, Conditions[i]);
//                        	}
//                        }
//                        queryObject.setFirstResult((page.getPageNumber() - 1) * pageSize);
//                        queryObject.setMaxResults(pageSize);
//                        return queryObject.list();
//                    }
//                });
//
//        page.setData(data);
//        return page;
        return null;
    }

    /**
     * 空っぽなPageを創立します、そしてdataをpageのdataの中に置きます。
     * @param data 　データー
     * @return page
     */
    public Page putDataToPage(List data) {
        Page result = new HibernatePage(data.size()+1, 1, data.size());
        result.setData(data);
        return result;
    }




    /**
     * The <code>HibernatePage</code> class represents an adapter object.
     *
     * @author  廖宝俊
     * @version 1.0, 2010-8-23
     */
    public class HibernatePage implements Page {
        /** 当面ページのデーター */
        private List data;
        /**
         *
         */
        private int pageSize;
        /** 総ページ数 */
        private int totalPage;
        /** 当面のページ番号 */
        private int pageNumber;

        /**総記録数*/
        private int totalSize;

        /**
         * 構造の方法
         * @param pageSize       ページサイズ
         * @param pageNumber    当面のページ番号
         * @param recordNumber  総記録数
         */
        HibernatePage(int pageSize, int pageNumber, int recordNumber) {
            this.pageSize = pageSize;
            this.pageNumber = pageNumber;
            this.totalPage = (int) Math.ceil((double) recordNumber / (double) pageSize);
            this.totalSize = recordNumber;
            //当面のページ番号を確定する
            if (this.pageNumber < 1) {
                this.pageNumber = 1;
            }
            if (this.pageNumber > this.totalPage) {
                this.pageNumber = this.totalPage;
            }
        }

        /**
         * 構造の方法：空っぽなPageを創立する.
         */
        HibernatePage() {
            this.data = Collections.EMPTY_LIST;
            this.totalPage = 0;
            this.pageNumber = 0;
//            this.pageSize = pageSize;
        }


        public void setData(List data) {
            this.data = data;
        }


        public int getTotalPage() {
            return this.totalPage;
        }

        public int getPageNumber() {
            return this.pageNumber;
        }

        public boolean getHasPreviousPage() {
            return this.pageNumber > 1;
        }

        public boolean getHasNextPage() {
            return this.pageNumber < this.totalPage;
        }

        public List getData() {
            return this.data;
        }

        public int getPageSize() {
            return pageSize;
        }

        public int getTotalSize() {
            return totalSize;
        }

		public void setPageSize(int pageSize) {
			this.pageSize = pageSize;
		}
    }

	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
}
